open Ast

let ecriture oo pere child cpt =
  begin
    let temp = "var" ^ string_of_int cpt in
    let aux = temp ^ " [label=\"" ^ child ^ "\"];\n" in
    output_string oo aux ; 
    let aux2 = pere ^ " -> " ^ temp ^ ";\n" in
    output_string oo aux2 ;
    let cpt2 = cpt + 1 in
    cpt2
   end 
;;

let rec genereDotOperateur operateur =  
  match operateur with
  Plus -> "+"
  | Moins -> "-"
  | Mult -> "*"
  | Div -> "/"
;;

let rec genereDotComparateur comparateur = 
  match comparateur with
  Inf -> "<"
  | Sup -> ">" 
  | InfEgal -> "<="
  | SupEgal -> ">="
  | Egal -> "=="
  | Diff -> "!=" 
;;

let rec genereDotArithmetique2 a =
  match a with
  | NVariable (nom,entry) -> nom
  | _ -> ""
;;

let rec genereDotArithmetique a oo pere test cpt = 
  match a with
  NN (entier) -> begin 
                    let aux = string_of_int (entier) in
                    let cpt2 = ecriture oo pere aux cpt in
                    cpt2
                  end
  | NVariable (nom,entry) -> 
          begin 
            let aux = nom ^ " : " ^ string_of_int(entry.entry) in 
            let cpt2 = ecriture oo pere aux cpt in
            cpt2
          end
  | NUnop (a) -> begin 
                    let aux = "-" in
                    let aux2 = "var" ^ string_of_int cpt in
                    let cpt2 = ecriture oo pere aux cpt in
                    let cpt3 = genereDotArithmetique a oo aux2 0 cpt2 in
                    cpt3
                  end
  | NBinOp (a1,op,a2) -> begin 
                            let aux = genereDotOperateur(op) in
                            let aux2 = "var" ^ string_of_int cpt in
                            let cpt2 = ecriture oo pere aux cpt in
                            let cpt3 = genereDotArithmetique a1 oo aux2 0 cpt2 in 
                            let cpt4 = genereDotArithmetique a2 oo aux2 0 cpt3 in
                            cpt4
                          end
;;

let rec genereDotArithmetiqueListeRec liste oo pere cpt = 
  match liste with 
    [] -> cpt
  | h::q ->  
        begin
          let cpt2 = genereDotArithmetique h oo pere 0 cpt in
          genereDotArithmetiqueListeRec q oo pere cpt2
        end
;;

let rec genereDotArithmetiqueListe al oo pere cpt=
  match al with 
  ArL(nArithmetique) -> 
            begin 
              let cpt2 = genereDotArithmetiqueListeRec nArithmetique oo pere cpt in
              cpt2
            end
;;  

let rec genereDotAppel appel oo pere cpt =
  match appel with
  NAppel (nom,arguments) -> 
              begin
                let aux = "CallFunction\\n" ^ nom in 
                let aux2 = "var" ^ string_of_int cpt in
                let cpt2 = ecriture oo pere aux cpt in
                let cpt3 = genereDotArithmetiqueListe arguments oo aux2 cpt2 in
                cpt3
              end
;;

let rec genereDotInstruction instruction oo pere cpt =
  match instruction with
  NReturn -> 
                        begin
                          let aux = "return" in 
                          let cpt2 = ecriture oo pere aux cpt in
                          cpt2 
                        end
  | NReturnValeur (valeur) -> 
                        begin 
                          let aux = "return" in
                          let aux2 = "var" ^ string_of_int cpt in
                          let cpt2 = ecriture oo pere aux cpt in
                          let cpt3 = genereDotArithmetique valeur oo aux2 0 cpt2 in
                          cpt3
                        end
  | NAffectation (variable,valeur) -> 
                        begin 
                          let aux = ":=" in
                          let aux2 = "var" ^ string_of_int cpt in
                          let cpt2 = ecriture oo pere aux cpt in
                          let cpt3 = genereDotArithmetique variable oo aux2 0 cpt2 in
                          let cpt4 = genereDotArithmetique valeur oo aux2 0 cpt3 in
                          cpt4
                        end
  | NAppelMethode (appel) -> 
                        begin
                          let cpt2 = genereDotAppel appel oo pere cpt in
                          cpt2
                        end  
  | NAppelFonction (variable,appel) -> 
                        begin 
                          let temp = "var" ^ string_of_int cpt in 
                          let cpt2 = genereDotAppel appel oo pere cpt in
                          let cpt3 = genereDotArithmetique variable oo temp 0 cpt2 in
                          cpt3
                        end
;;

let rec genereDotBoolean boolean oo pere cpt =
  match boolean with
  NTrue ->  
        begin
          let aux = "true" in
          let cpt2 = ecriture oo pere aux cpt in
          cpt2
        end 
  | NFalse -> 
        begin
          let aux = "false" in 
          let cpt2 = ecriture oo pere aux cpt in
          cpt2
        end 
  | NCmp (a1,comparateur,a2) -> 
                          begin
                            let aux = genereDotComparateur(comparateur) in
                            let aux2 = "var" ^ string_of_int cpt in
                            let cpt2 = ecriture oo pere aux cpt in
                            let cpt3 = genereDotArithmetique a1 oo aux2 0 cpt2 in 
                            let cpt4 = genereDotArithmetique a2 oo aux2 0 cpt3 in
                            cpt4
                          end
  | NotBoolean (boolean) -> 
                          begin 
                            let aux ="!" in
                            let aux2 = "var" ^ string_of_int cpt in
                            let cpt2 = ecriture oo pere aux cpt in
                            let cpt3 = genereDotBoolean boolean oo aux2 cpt2 in
                            cpt3  
                          end
  | NOr (booleen1,booleen2) -> 
                          begin 
                            let aux ="OR" in
                            let aux2 = "var" ^ string_of_int cpt in
                            let cpt2 = ecriture oo pere aux cpt in
                            let cpt3 = genereDotBoolean booleen1 oo aux2 cpt2 in 
                            let cpt4 = genereDotBoolean booleen2 oo aux2 cpt3 in
                            cpt4
                          end
  | NAnd (booleen1,booleen2) -> 
                          begin 
                            let aux ="AND" in
                            let aux2 = "var" ^ string_of_int cpt in
                            let cpt2 = ecriture oo pere aux cpt  in
                            let cpt3 = genereDotBoolean booleen1 oo aux2 cpt2 in
                            let cpt4 = genereDotBoolean booleen2 oo aux2 cpt3 in
                            cpt4
                          end
;;

let rec genereDotVariableListeRec liste leType res= 
  match liste with  
    [] -> res
  | h::q -> 
          begin
            let aux = genereDotArithmetique2 h in
            let res2 = res ^ "\\n" ^ leType ^ " " ^ aux in
            genereDotVariableListeRec q leType res2
          end
;;

let rec genereDotVariableListe noeud leType=
  match noeud with 
  | ListeVariable(nArithmetique) ->
            begin
              let res = genereDotVariableListeRec nArithmetique leType "" in
              res
            end
;;

let rec genereDotDeclaration noeud =
  match noeud with 
  | NDeclaration(leType,variableListe) -> 
  begin
    let res = genereDotVariableListe variableListe leType in
    res
  end
;;

let rec genereDotDeclarationsListeRec liste res = 
  match liste with
    [] -> res
  | h::q -> 
      begin
        let aux = genereDotDeclaration h in 
        let res2 = res ^ "\\n" ^ aux in
        genereDotDeclarationsListeRec q res2
      end   

let rec genereDotDeclarationsListe noeud =
  match noeud with
  | DecList(nDeclaration) -> 
                    begin
                      let res = genereDotDeclarationsListeRec nDeclaration "" in
                      res
                    end
;;


let rec genereDotStatementRec liste oo pere cpt = 
  match liste with
  | [] -> cpt
  | h::q -> 
        begin
          let cpt2 = genereDotStatement h oo pere cpt in 
          genereDotStatementRec q oo pere cpt2
        end
 
and 

 genereDotStatement noeud oo pere cpt =
  match noeud with
   NStatementInstruction(nInstruction) -> 
          begin
            let cpt2 = genereDotInstruction nInstruction oo pere cpt in
            cpt2
          end
  | NIf(nBoolean,nStatement,nStatement2) -> 
          begin
            let aux = "If" in
            let aux2 = "var" ^ string_of_int cpt in 
            let cpt2 = ecriture oo pere aux cpt in
            let cpt3 = genereDotBoolean nBoolean oo aux2 cpt2 in
            let cpt4 = genereDotStatement nStatement oo aux2 cpt3 in
            let cpt5 = genereDotStatement nStatement2 oo aux2 cpt4 in
            cpt5 
          end
  | NWhile(nBoolean,nStatement) ->
          begin
            let aux = "While" in
            let aux2 = "var" ^ string_of_int cpt in 
            let cpt2 = ecriture oo pere aux cpt in
            let cpt3 = genereDotBoolean nBoolean oo aux2 cpt2 in
            let cpt4 = genereDotStatement nStatement oo aux2 cpt3  in
            cpt4             
          end    
  | NBlock(declarationsListe,statementsListe) ->
          begin
            let aux = "Block" in
            let aux2 = "var" ^ string_of_int cpt in 
            let aux3 = aux ^ genereDotDeclarationsListe declarationsListe in
            let cpt2 = ecriture oo pere aux3 cpt in
            let cpt3 = genereDotStatementRec statementsListe oo aux2 cpt2 in
            cpt3
          end
;;


let rec genereDotExpression noeud oo pere cpt =
  match noeud with 
   Na(nArithmetique) -> 
            begin 
              let cpt2 = genereDotArithmetique nArithmetique oo pere 0 cpt in
              cpt2 
            end
  | Nb(nBoolean) -> 
            begin
              let cpt2 = genereDotBoolean nBoolean oo pere cpt in
              cpt2
            end 
;;

let rec genereDotArgument noeud = 
  match noeud with 
  NArgument(nArithmetique,leType) ->
        begin
          let temp = genereDotArithmetique2 nArithmetique  in
          let temp2 = "\\n" ^ leType ^ " " ^ temp in
          temp2        
        end
;;

let rec genereDotArgumentsdeclarationListeRec liste res = 
  match liste with
  | [] -> res
  | h::q -> 
        begin
          let aux = genereDotArgument h in
          let res2 = res ^ aux in
          genereDotArgumentsdeclarationListeRec q res2
        end
;;

let rec genereDotArgumentsdeclarationListe noeud = 
  match noeud with
  Al(nArgument) ->  
                  begin
                    let res = genereDotArgumentsdeclarationListeRec nArgument "" in
                    res
                  end
;;

let rec genereDotProcedure noeud oo pere cpt =
  match noeud with
  NProcedure(nom,adl,nst) -> 
        begin
          let aux = "Procedure\\n" ^ nom in
          let temp = "var" ^ string_of_int cpt in
          let aux2 = aux ^ genereDotArgumentsdeclarationListe adl in
          let cpt2 = ecriture oo pere aux2 cpt in
          let cpt3 = genereDotStatement nst oo temp cpt2 in
          cpt3
        end
;;

let rec genereDotFonction noeud oo pere cpt =
  match noeud with 
  NFonction(nom,adl,typeRetour,nst) ->  
        begin
          let aux = "Fonction\\n" ^ nom in
          let temp = "var" ^ string_of_int cpt in
          let aux2 = aux ^ genereDotArgumentsdeclarationListe adl in 
          let cpt2 = ecriture oo pere aux2 cpt in
          let cpt3 = ecriture oo temp typeRetour cpt2 in
          let cpt4 = genereDotStatement nst oo temp cpt3 in
          cpt4  
        end
;;  

let rec genereDotProgramme noeud oo pere cpt =
  match noeud with 
  | NProgrammeProcedure(nProcedure) -> 
        begin
          let cpt2 = genereDotProcedure nProcedure oo pere cpt in
          cpt2
        end
  | NProgrammeFonction(nFonction) -> 
        begin
          let cpt2 = genereDotFonction nFonction oo pere cpt in
          cpt2
        end
;;

let rec genereDotNoeudPrincipalRec liste oo pere cpt first= 
  match liste with
  | [] -> cpt  
  | h::q -> 
          begin
            let aux = "var" ^ string_of_int first in
            let cpt2 = genereDotProgramme h oo aux cpt in
            genereDotNoeudPrincipalRec q oo aux cpt2 first
          end

let testtest oo = 
  output_string oo "\"test\" -> \"test2\"";;

let faitrien a =
  print_string ""

let rec genereDotNoeudPrincipal noeud = 
  match noeud with
  | Programme(fonctions,main) -> 
    begin
      let oo = open_out "arbreSyntaxe.dot" in
      output_string oo "digraph G {";
      (*testtest oo ;*)
      output_string oo "\nvar0 [label=\"Programme\"];\n";
      let cpt = genereDotNoeudPrincipalRec fonctions oo "var0" 1 0 in
      let cpt2 = genereDotStatement main oo "var0" cpt in
      begin
        output_string oo "}";
        close_out oo ;
        faitrien cpt2;
        print_string ""
      end;
      print_string ""
    end
;;


